home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / ole2book.zip / CHAP09.ZIP / CHAP09 / PATRON / IDROPTGT.CPP < prev    next >
C/C++ Source or Header  |  1993-06-01  |  14KB  |  550 lines

  1. /*
  2.  * IDROPTGT.CPP
  3.  *
  4.  * Implementation of a DropTarget object for Patron
  5.  *
  6.  * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  7.  *
  8.  * Kraig Brockschmidt, Software Design Engineer
  9.  * Microsoft Systems Developer Relations
  10.  *
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include "patron.h"
  17.  
  18.  
  19.  
  20. /*
  21.  * CDropTarget::CDropTarget
  22.  * CDropTarget::~CDropTarget
  23.  *
  24.  * Constructor Parameters:
  25.  *  pDoc            LPCPatronDoc of the window containing us.
  26.  */
  27.  
  28. CDropTarget::CDropTarget(LPCPatronDoc pDoc)
  29.     {
  30.     m_cRef=0;
  31.     m_pDoc=pDoc;
  32.  
  33.     m_pIDataObject=NULL;
  34.     return;
  35.     }
  36.  
  37.  
  38. CDropTarget::~CDropTarget(void)
  39.     {
  40.     return;
  41.     }
  42.  
  43.  
  44.  
  45.  
  46. /*
  47.  * CDropTarget::QueryInterface
  48.  * CDropTarget::AddRef
  49.  * CDropTarget::Release
  50.  *
  51.  * Purpose:
  52.  *  IUnknown members for CDropTarget object.
  53.  */
  54.  
  55. STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  56.     {
  57.     *ppv=NULL;
  58.  
  59.     //Any interface on this object is the object pointer.
  60.     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDropTarget))
  61.         *ppv=(LPVOID)this;
  62.  
  63.     /*
  64.      * If we actually assign an interface to ppv we need to AddRef it
  65.      * since we're returning a new pointer.
  66.      */
  67.     if (NULL!=*ppv)
  68.         {
  69.         ((LPUNKNOWN)*ppv)->AddRef();
  70.         return NOERROR;
  71.         }
  72.  
  73.     return ResultFromScode(E_NOINTERFACE);
  74.     }
  75.  
  76.  
  77. STDMETHODIMP_(ULONG) CDropTarget::AddRef(void)
  78.     {
  79.     return ++m_cRef;
  80.     }
  81.  
  82. STDMETHODIMP_(ULONG) CDropTarget::Release(void)
  83.     {
  84.     ULONG           cRefT;
  85.  
  86.     cRefT=--m_cRef;
  87.  
  88.     if (0L==m_cRef)
  89.         delete this;
  90.  
  91.     return cRefT;
  92.     }
  93.  
  94.  
  95.  
  96.  
  97.  
  98. /*
  99.  * CDropTarget::DragEnter
  100.  *
  101.  * Purpose:
  102.  *  Indicates that data in a drag operation has been dragged over our
  103.  *  window that's a potential target.  We are to decide if it's something
  104.  *  we're interested in or not.
  105.  *
  106.  * Parameters:
  107.  *  pIDataSource    LPDATAOBJECT providing the source data.
  108.  *  grfKeyState     DWORD flags indicating states of keys and mouse buttons.
  109.  *  pt              POINTL coordinates in the client space of the document.
  110.  *  pdwEffect       LPDWORD into which we'll place the appropriate effect
  111.  *                  flag for this point.
  112.  *
  113.  * Return Value:
  114.  *  SCODE           NOERROR
  115.  */
  116.  
  117. STDMETHODIMP CDropTarget::DragEnter(LPDATAOBJECT pIDataSource
  118.     , DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
  119.     {
  120.     LPCPages        ppg=m_pDoc->m_pPG;
  121.     HWND            hWnd;
  122.     FORMATETC       fe;
  123.     STGMEDIUM       stm;
  124.     UINT            uRet;
  125.  
  126.     m_fFeedback=FALSE;
  127.     m_pIDataObject=NULL;
  128.  
  129.     if (!m_pDoc->FQueryPasteFromData(pIDataSource, &fe, NULL))
  130.         {
  131.         *pdwEffect=DROPEFFECT_NONE;
  132.         return NOERROR;
  133.         }
  134.  
  135.     //Check if this is a valid drop point.
  136.     uRet=ppg->UTestDroppablePoint(&pt);
  137.     ppg->m_uLastTest=uRet;
  138.  
  139.     if (UDROP_NONE==uRet)
  140.         *pdwEffect=DROPEFFECT_NONE;
  141.     else
  142.         {
  143.         //Default is move if we can, in fact drop here.
  144.         *pdwEffect=DROPEFFECT_MOVE;
  145.  
  146.         if (grfKeyState & MK_CONTROL)
  147.             *pdwEffect=DROPEFFECT_COPY;
  148.         }
  149.  
  150.     m_pIDataObject=pIDataSource;
  151.     m_pIDataObject->AddRef();
  152.  
  153.     /*
  154.      * Determine the size of the data, if we can.  The default is
  155.      * a small rectangle since we can't easily tell what size something
  156.      * will be if we're pulling in a metafile or bitmap.  It's not
  157.      * a good idea to render it here with ::GetData just to find that out.
  158.      * We only know the size if it's our own object in which case a
  159.      * ::GetData will be fast.
  160.      */
  161.  
  162.     if (fe.cfFormat==m_pDoc->m_cf)
  163.         {
  164.         if (SUCCEEDED(pIDataSource->GetData(&fe, &stm)))
  165.             {
  166.             LPPATRONOBJECT  ppo;
  167.             RECT            rc;
  168.  
  169.             ppo=(LPPATRONOBJECT)GlobalLock(stm.hGlobal);
  170.  
  171.             SetRect(&rc, (int)ppo->szl.cx, -(int)ppo->szl.cy, 0, 0);
  172.             RectConvertMappings(&rc, NULL, TRUE);
  173.             SETSIZEL(m_szl, rc.left, rc.top);
  174.  
  175.             m_ptPick=ppo->ptlPick;
  176.             m_fe=ppo->fe;
  177.  
  178.             GlobalUnlock(stm.hGlobal);
  179.             ReleaseStgMedium(&stm);
  180.             }
  181.         }
  182.     else
  183.         {
  184.         SETSIZEL(m_szl, 30, 30);
  185.         m_ptPick.x=0;
  186.         m_ptPick.y=0;
  187.         m_fe.cfFormat=0;
  188.  
  189.         //CHAPTER9MOD
  190.         /*
  191.          * Try to get CF_OBJECTDESCRIPTOR which might have a size and
  192.          * a pick point.  If it exists, then always use the point but
  193.          * still default to a 30*30 size if the sizes are zero.
  194.          */
  195.         uRet=RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);
  196.         SETDefFormatEtc(fe, uRet, TYMED_HGLOBAL);
  197.  
  198.         if (SUCCEEDED(pIDataSource->GetData(&fe, &stm)))
  199.             {
  200.             LPOBJECTDESCRIPTOR  pOD;
  201.  
  202.             pOD=(LPOBJECTDESCRIPTOR)GlobalLock(stm.hGlobal);
  203.  
  204.             //Get the size, converting to LOMETRIC.
  205.             if (0!=pOD->sizel.cx && 0!=pOD->sizel.cy)
  206.                 XformSizeInHimetricToPixels(NULL, &pOD->sizel, &m_szl);
  207.  
  208.             //POINTL and SIZEL are interchangeable
  209.             XformSizeInHimetricToPixels(NULL, (LPSIZEL)&pOD->pointl
  210.                 , (LPSIZEL)&m_ptPick);
  211.  
  212.             GlobalUnlock(stm.hGlobal);
  213.             ReleaseStgMedium(&stm);
  214.             }
  215.         //End CHAPTER9MOD
  216.         }
  217.  
  218.  
  219.     //Bring the document window up front and show what a drop will do.
  220.     hWnd=m_pDoc->Window();
  221.     BringWindowToTop(hWnd);
  222.     UpdateWindow(hWnd);
  223.  
  224.     ppg->m_uVScrollCode=0xFFFF;
  225.     ppg->m_uHScrollCode=0xFFFF;
  226.     m_fPendingRepaint=FALSE;
  227.  
  228.     pt.x-=m_ptPick.x;
  229.     pt.y-=m_ptPick.y;
  230.  
  231.     m_ptLast=pt;
  232.     m_fFeedback=TRUE;
  233.     ppg->DrawDropTargetRect(&pt, &m_szl);
  234.  
  235.     return NOERROR;
  236.     }
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243. /*
  244.  * CDropTarget::DragOver
  245.  *
  246.  * Purpose:
  247.  *  Indicates that the mouse was moved inside the window represented
  248.  *  by this drop target.  This happens on every WM_MOUSEMOVE, so this
  249.  *  function should be very efficient.
  250.  *
  251.  * Parameters:
  252.  *  grfKeyState     DWORD providing the current keyboard and mouse states
  253.  *  pt              POINTL where the mouse currently is.
  254.  *  pdwEffect       LPDWORD in which to store the effect flag for this point.
  255.  *
  256.  * Return Value:
  257.  *  SCODE           NOERROR
  258.  */
  259.  
  260. STDMETHODIMP CDropTarget::DragOver(DWORD grfKeyState, POINTL pt
  261.     , LPDWORD pdwEffect)
  262.     {
  263.     LPCPages    ppg=m_pDoc->m_pPG;
  264.     UINT        uRet, uLast;
  265.     UINT        xPos, yPos;
  266.  
  267.     if (NULL==m_pIDataObject)
  268.         return NOERROR;
  269.  
  270.     //Check if this is still a valid point.  uRet is used below as well.
  271.     uRet=ppg->UTestDroppablePoint(&pt);
  272.  
  273.     if (UDROP_NONE==uRet)
  274.         *pdwEffect=DROPEFFECT_NONE;
  275.     else
  276.         {
  277.         //Store these before possibly ORing in DROPEFFECT_SCROLL
  278.         *pdwEffect=DROPEFFECT_MOVE;
  279.  
  280.         if (grfKeyState & MK_CONTROL)
  281.             *pdwEffect=DROPEFFECT_COPY;
  282.         }
  283.  
  284.     //If we haven't moved and we are not scrolling, then we're done.
  285.     if ((pt.x-m_ptPick.x==m_ptLast.x) && (pt.y-m_ptPick.y==m_ptLast.y)
  286.         && !((UDROP_INSETHORZ | UDROP_INSETVERT) & ppg->m_uLastTest))
  287.         {
  288.         return NOERROR;
  289.         }
  290.  
  291.     //Remove the last feedback rectangle.
  292.     if (m_fFeedback)
  293.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  294.  
  295.     uLast=ppg->m_uLastTest;
  296.     ppg->m_uLastTest=uRet;
  297.  
  298.     if (UDROP_NONE==uRet)
  299.         {
  300.         //If we are now an invalid point, better repaint as necessary
  301.         if (m_fPendingRepaint)
  302.             {
  303.             UpdateWindow(ppg->m_hWnd);
  304.             m_fPendingRepaint=FALSE;
  305.             }
  306.  
  307.         ppg->m_uVScrollCode=0xFFFF;
  308.         ppg->m_uHScrollCode=0xFFFF;
  309.         m_fFeedback=FALSE;
  310.         return NOERROR;
  311.         }
  312.  
  313.  
  314.     /*
  315.      * Scrolling is a little tricky:  We get a DragOver pulse even
  316.      * if we didn't move.  First we have to delay scrolling for
  317.      * ppg->m_uScrollDelay clock ticks which we can determine using
  318.      * GetTickCount.  Timers do not work here since we may not be
  319.      * yielding to our message loop.
  320.      *
  321.      * Once we know we are scrolling then we determine if we
  322.      * scroll again or if we reset the scrolling state.
  323.      */
  324.  
  325.     if ((UDROP_INSETHORZ & uLast) && !(UDROP_INSETHORZ & uRet))
  326.         ppg->m_uHScrollCode=0xFFFF;
  327.  
  328.     if (!(UDROP_INSETHORZ & uLast) && (UDROP_INSETHORZ & uRet))
  329.         {
  330.         ppg->m_dwTimeLast=GetTickCount();
  331.         ppg->m_uHScrollCode=(0!=(UDROP_INSETLEFT & uRet))
  332.             ? SB_LINELEFT : SB_LINERIGHT;   //Same as UP & DOWN codes.
  333.         }
  334.  
  335.     if ((UDROP_INSETVERT & uLast) && !(UDROP_INSETVERT & uRet))
  336.         ppg->m_uVScrollCode=0xFFFF;
  337.  
  338.     if (!(UDROP_INSETVERT & uLast) && (UDROP_INSETVERT & uRet))
  339.         {
  340.         ppg->m_dwTimeLast=GetTickCount();
  341.         ppg->m_uVScrollCode=(0!=(UDROP_INSETTOP & uRet))
  342.             ? SB_LINEUP : SB_LINEDOWN;
  343.         }
  344.  
  345.     //Only change the last time if ALL scrolling stops.
  346.     if (0xFFFF==ppg->m_uHScrollCode && 0xFFFF==ppg->m_uVScrollCode)
  347.         ppg->m_dwTimeLast=0L;
  348.  
  349.     //Set the scroll effect on any inset hit.
  350.     if ((UDROP_INSETHORZ | UDROP_INSETVERT) & uRet)
  351.         *pdwEffect |= DROPEFFECT_SCROLL;
  352.  
  353.     xPos=ppg->m_xPos;
  354.     yPos=ppg->m_yPos;
  355.  
  356.     //Has the delay elapsed?  We can scroll if so
  357.     if (ppg->m_dwTimeLast!=0
  358.         && (GetTickCount()-ppg->m_dwTimeLast) > (DWORD)ppg->m_uScrollDelay)
  359.         {
  360.         if (0xFFFF!=ppg->m_uHScrollCode)
  361.             {
  362.             m_fPendingRepaint=TRUE;
  363.             SendMessage(ppg->m_hWnd, WM_HSCROLL, ppg->m_uHScrollCode, 0L);
  364.             }
  365.  
  366.         if (0xFFFF!=ppg->m_uVScrollCode)
  367.             {
  368.             m_fPendingRepaint=TRUE;
  369.             SendMessage(ppg->m_hWnd, WM_VSCROLL, ppg->m_uVScrollCode, 0L);
  370.             }
  371.         }
  372.  
  373.     //If we didn't scroll anywhere by have a pending repaint, do it now.
  374.     if (xPos==ppg->m_xPos && yPos==ppg->m_yPos && m_fPendingRepaint)
  375.         {
  376.         UpdateWindow(ppg->m_hWnd);
  377.         m_fPendingRepaint=FALSE;
  378.         }
  379.  
  380.     pt.x-=m_ptPick.x;
  381.     pt.y-=m_ptPick.y;
  382.  
  383.     m_ptLast=pt;
  384.     m_fFeedback=TRUE;
  385.     ppg->DrawDropTargetRect(&pt, &m_szl);
  386.  
  387.     return NOERROR;
  388.     }
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395. /*
  396.  * CDropTarget::DragLeave
  397.  *
  398.  * Purpose:
  399.  *  Informs the drop target that the operation has left its window.
  400.  *
  401.  * Parameters:
  402.  *  None
  403.  *
  404.  * Return Value:
  405.  *  SCODE           NOERROR
  406.  */
  407.  
  408. STDMETHODIMP CDropTarget::DragLeave(void)
  409.     {
  410.     LPCPages        ppg=m_pDoc->m_pPG;
  411.  
  412.     if (NULL==m_pIDataObject)
  413.         return NOERROR;
  414.  
  415.     //Stop scrolling
  416.     ppg->m_uHScrollCode=0xFFFF;
  417.     ppg->m_uVScrollCode=0xFFFF;
  418.  
  419.     if (m_fPendingRepaint)
  420.         UpdateWindow(ppg->m_hWnd);
  421.  
  422.     //Remove the last feedback rectangle.
  423.     if (m_fFeedback)
  424.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  425.  
  426.     m_fFeedback=FALSE;
  427.     m_pIDataObject->Release();
  428.     return NOERROR;
  429.     }
  430.  
  431.  
  432.  
  433.  
  434.  
  435. /*
  436.  * CDropTarget::Drop
  437.  *
  438.  * Purpose:
  439.  *  Instructs the drop target to paste the data that was just now dropped
  440.  *  on it.
  441.  *
  442.  * Parameters:
  443.  *  pIDataSource    LPDATAOBJECT from which we'll paste.
  444.  *  grfKeyState     DWORD providing current keyboard/mouse state.
  445.  *  pt              POINTL at which the drop occurred.
  446.  *  pdwEffect       LPDWORD in which to store what you do with the data.
  447.  *
  448.  * Return Value:
  449.  *  SCODE           NOERROR
  450.  */
  451.  
  452. STDMETHODIMP CDropTarget::Drop(LPDATAOBJECT pIDataSource
  453.     , DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
  454.     {
  455.     LPCPages        ppg=m_pDoc->m_pPG;
  456.     BOOL            fRet=TRUE;
  457.     FORMATETC       fe;
  458.     TENANTTYPE      tType;
  459.     PATRONOBJECT    po;
  460.     POINT           ptS;
  461.  
  462.     *pdwEffect=DROPEFFECT_NONE;
  463.  
  464.     if (NULL==m_pIDataObject)
  465.         return ResultFromScode(E_FAIL);
  466.  
  467.     if (UDROP_NONE==ppg->UTestDroppablePoint(&pt))
  468.         return ResultFromScode(E_FAIL);
  469.  
  470.     //Stop scrolling
  471.     ppg->m_uHScrollCode=0xFFFF;
  472.     ppg->m_uVScrollCode=0xFFFF;
  473.  
  474.     if (m_fPendingRepaint)
  475.         UpdateWindow(ppg->m_hWnd);
  476.  
  477.     //2.  Remove the UI feedback
  478.     if (m_fFeedback)
  479.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  480.  
  481.     m_pIDataObject->Release();
  482.  
  483.  
  484.     /*
  485.      * Check if we can do the paste, and if so, tell our pasting
  486.      * mechanism exactly where to place us.
  487.      */
  488.     pt.x-=m_ptPick.x;
  489.     pt.y-=m_ptPick.y;
  490.  
  491.     POINTFROMPOINTL(ptS, pt);
  492.     ScreenToClient(ppg->Window(), &ptS);
  493.     POINTLFROMPOINT(po.ptl, ptS);
  494.  
  495.     //This condition is true if we didn't see placement data in DragEnter
  496.     if (0!=m_fe.cfFormat)
  497.         {
  498.         po.szl.cx=m_szl.cx;         //We stored these positive
  499.         po.szl.cy=-m_szl.cy;
  500.         }
  501.     else
  502.         SETSIZEL(po.szl, 0, 0); //Ask object for its size.
  503.  
  504.     //Adjust for scrolling and mapping mode.
  505.     ppg->AdjustPosition(&po.ptl, &po.szl);
  506.  
  507.  
  508.     /*
  509.      * If we're in the same document and moving, then we can just
  510.      * stuff the Pages' m_ptDrop which will move us and return.
  511.      */
  512.     if (ppg->m_fDragSource && !(grfKeyState & MK_CONTROL))
  513.         {
  514.         *pdwEffect=DROPEFFECT_MOVE;
  515.         ppg->m_fMoveInPage=TRUE;
  516.         ppg->m_ptDrop=po.ptl;
  517.         return NOERROR;
  518.         }
  519.  
  520.     /*
  521.      * Otherwise, paste either from another document or from
  522.      * the same document which will always be a copy to the new point.
  523.      */
  524.  
  525.     ppg->m_fMoveInPage=FALSE;
  526.     fRet=m_pDoc->FQueryPasteFromData(pIDataSource, &fe, &tType);
  527.  
  528.     if (fRet)
  529.         {
  530.         //Copy the real format if we have placement data.
  531.         po.fe=(m_pDoc->m_cf==fe.cfFormat) ? m_fe : fe;
  532.  
  533.         //CHAPTER9MOD
  534.         //Flag FPasteFromData to use CF_OBJECTDESCRIPTOR
  535.         fRet=m_pDoc->FPasteFromData(pIDataSource, &fe, tType, &po, 0, TRUE);
  536.         //End CHAPTER9MOD
  537.         }
  538.  
  539.     if (!fRet)
  540.         return ResultFromScode(E_FAIL);
  541.  
  542.  
  543.     *pdwEffect=DROPEFFECT_MOVE;
  544.  
  545.     if (grfKeyState & MK_CONTROL)
  546.         *pdwEffect=DROPEFFECT_COPY;
  547.  
  548.     return NOERROR;
  549.     }
  550.